package com.authine.cloudpivot.app.openapi.executor;

import com.authine.cloudpivot.app.openapi.constants.RedisKeyConstant;
import com.authine.cloudpivot.app.openapi.domain.openapi.AppConfigValue;
import com.authine.cloudpivot.app.openapi.domain.openapi.OpenApi;
import com.authine.cloudpivot.app.openapi.domain.openapi.UserInfoValue;
import com.authine.cloudpivot.app.openapi.dto.GenerateTokenRes;
import com.authine.cloudpivot.app.openapi.util.OpenApiUtils;
import com.authine.hermes.lib.cloudpivot.cache.core.CacheExpires;
import com.authine.hermes.lib.cloudpivot.cache.core.command.RedisHashMap;
import com.authine.hermes.lib.cloudpivot.cache.core.command.RedisObject;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Objects;

/**
 * @author lifuchun
 */
@Service
public class GenerateOpenApiTokenExe {

    private final OpenApi openApi;

    public GenerateOpenApiTokenExe(OpenApi openApi) {
        this.openApi = openApi;
    }

    public GenerateTokenRes execute(String appKey, String userId, String nonce, String sign) {
        //校验输入参数
        validateParam(appKey, userId, nonce, sign);
        //从缓存中获取app信息
        AppConfigValue appConfigValue = getAppConfigValueFromCache(appKey);
        //校验签名
        checkSign(userId, nonce, sign, appConfigValue);
        //获取从组织结构服务用户信息
        UserInfoValue userInfoValue = getUserInfoFromOrgServiceStep(userId, appConfigValue.getCorpId());
        //生成token
        String token = buildToken();
        //清理用户缓存，并重建token缓存
        cleanAndBuildCache(token, userInfoValue, appConfigValue);
        //登记获取授权的userId
        recordTokenUserIdInfo(appConfigValue, userId);
        //获取过期时间
        long expireTime = getExpireTime(appConfigValue);
        //返回token和过期时间
        return GenerateTokenRes.builder().token(token).expireTime(expireTime).build();

    }

    private void checkSign(String userId, String nonce, String sign, AppConfigValue appConfigValue) {

        Assert.isTrue(OpenApiUtils.checkSignNoDependency(userId, nonce, sign, appConfigValue.getAppKey(), appConfigValue.getAppSecret()),
                "请按照文档规约进行签名");

    }

    private String buildToken() {
        return RandomStringUtils.randomAlphabetic(32).toLowerCase();
    }

    private void cleanAndBuildCache(String token, UserInfoValue userInfoValue, AppConfigValue appConfigValue) {
        String userId = userInfoValue.getOrgUserId();
        String appKey = appConfigValue.getAppKey();
        RedisObject redisObject = new RedisObject(String.format(RedisKeyConstant.KEY_USER_ID_APP_KEY, userId, appKey));

        if (!redisObject.exists() || Objects.isNull(redisObject.get())) {
            redisObject.set(token, CacheExpires.IN_1HOUR);
        } else {

            String oldToken = redisObject.get();
            RedisHashMap redisObject2 = new RedisHashMap(String.format(RedisKeyConstant.KEY_OPENAPI_TOKEN, oldToken));
            redisObject2.remove();
        }

        RedisHashMap redisObject3 = new RedisHashMap(String.format(RedisKeyConstant.KEY_OPENAPI_TOKEN, token));
        redisObject3.set(RedisKeyConstant.MAP_KEY_USER_INFO_VALUE, userInfoValue);
        redisObject3.set(RedisKeyConstant.MAP_KEY_APP_CONFIG_VALUE, appConfigValue);
        redisObject3.setExpire(CacheExpires.IN_1HOUR);

    }


    private AppConfigValue getAppConfigValueFromCache(String appKey) {

        RedisObject redisObject = new RedisObject(String.format(RedisKeyConstant.KEY_APP_CONFIG_VALUE, appKey));
        if (!redisObject.exists() || Objects.isNull(redisObject.get())) {
            AppConfigValue appConfigValue = openApi.getAppConfigValue(appKey);

            redisObject.set(appConfigValue, CacheExpires.IN_1DAY);

            return appConfigValue;
        }

        return redisObject.get();

    }

    private void validateParam(String appKey, String userId, String nonce, String sign) {

        Assert.isTrue(StringUtils.isNotBlank(appKey), "appKey不能为空");
        Assert.isTrue(appKey.trim().length() == 32, "appKey是32位字符");

        Assert.isTrue(StringUtils.isNotBlank(userId), "userId不能为空");

        Assert.isTrue(StringUtils.isNotBlank(nonce), "nonce不能为空");
        Assert.isTrue(nonce.trim().length() == 16, "nonce是16位字符");

        Assert.isTrue(StringUtils.isNotBlank(sign), "sign不能为空");

    }

    private void recordTokenUserIdInfo(AppConfigValue appConfigValue, String userId) {
        //登记授权登录过的用户
        openApi.recordTokenUserInfo(userId, appConfigValue.getAppKey());
    }

    private long getExpireTime(AppConfigValue appConfigValue) {
        return System.currentTimeMillis() + (1000 * appConfigValue.getExpireSecond().longValue());
    }


    private UserInfoValue getUserInfoFromOrgServiceStep(String userId, String corpId) {

        RedisObject redisObject = new RedisObject(String.format(RedisKeyConstant.KEY_USER_INFO_VALUE, userId, corpId));
        if (!redisObject.exists() || Objects.isNull(redisObject.get())) {
            UserInfoValue userInfoValue = openApi.getUserInfoValue(userId, corpId);
            redisObject.set(userInfoValue, CacheExpires.IN_1HOUR);
            return userInfoValue;
        }

        return redisObject.get();

    }

}
